/* eslint-disable prefer-spread */
type Handle = (...args: unknown[]) => void

type Handles = Record<string, Handle[]>

type EventType = string

export default abstract class Sub {
  private handles: Handles

  public constructor() {
    this.handles = Object.create(null);
  }

  /**
   * 添加监听事件
   */
  public on(eventType: EventType, handle: Handle) {
    if (!Object.prototype.hasOwnProperty.call(this.handles, eventType)) {
      this.handles[eventType] = [];
    }

    if (typeof handle === 'function') {
      this.handles[eventType].push(handle);
    } else {
      throw Error('缺少回调函数');
    }

    return this;
  }

  /**
   * 添加监听事件
   *
   */
  public once(eventType: EventType, handle: Handle) {
    const fn = (...args: unknown[]) => {
      handle.apply(null, args);
      this.off(eventType, fn);
    };

    this.on(eventType, fn);
    return this;
  }

  protected off(eventType: string, handle: Handle) {
    if (!Object.prototype.hasOwnProperty.call(this.handles, eventType)) {
      throw new Error(`"${eventType}"事件未注册`);
    } else if (typeof handle !== 'function') {
      throw Error('缺少回调函数');
    } else {
      this.handles[eventType].forEach((item, index, arr) => {
        if (item === handle) {
          arr.splice(index, 1);
        }
      });
    }
  }

  protected emit(eventType: EventType, ...args: unknown[]) {
    if (Object.prototype.hasOwnProperty.call(this.handles, eventType)) {
      this.handles[eventType].forEach((handle) => {
        handle.apply(null, args);
      });
    } else {
      throw new Error(`"${eventType}"事件未注册`);
    }

    return this;
  }
}
